#include "sbrush_pantomime_player.h"

using namespace std;
using namespace sbrush;
using namespace dag;

namespace {
	void sms_player_finished(const Player* player, void* userData) {
		PantomimePlayer* pantomimePlayer = static_cast<PantomimePlayer*>(userData);
		if (pantomimePlayer != NULL) {
			pantomimePlayer->finished();
		}
	}
}

PantomimePlayer::PantomimePlayer()
:	m_CurrentPantomime(NULL),
	m_IsRunning(false),
	m_KeepRunning(false),
	m_SampleQueue(SampleCompare())
{
	m_SpectralModelPlayer.setFinishedCallback(sms_player_finished, this);
}

PantomimePlayer::~PantomimePlayer() throw() {
	if (m_IsRunning) {
		stop();
		joinThread();
	}	
}

void PantomimePlayer::setPantomime(const Pantomime& pantomime) {
	if (m_IsRunning) {
		stop();
		joinThread();
	}
	{
		ScopedLock sl(m_PlayMutex);
		m_CurrentPantomime = &pantomime;
	}
}

void PantomimePlayer::addListener(InstrumentListener* listener) {
	ScopedLock sl(m_PlayMutex);
	m_Listeners.insert(listener);
}

void PantomimePlayer::removeListener(InstrumentListener* listener) {
	ScopedLock sl(m_PlayMutex);
	m_Listeners.erase(listener);
}

void PantomimePlayer::start() {
	if (m_IsRunning) {
		stop();
		joinThread();
	}
	{
		ScopedLock sl(m_PlayMutex);
		buildSampleQueue();
		startThread();
		m_SpectralModelPlayer.setModel(m_CurrentPantomime->getSpectralModel());
		m_SpectralModelPlayer.start();
	}
}

void PantomimePlayer::stop() {
	{
		ScopedLock sl(m_PlayMutex);
		m_KeepRunning = false;
		m_SpectralModelPlayer.stop();
	}
}

int PantomimePlayer::playHead() const {
	ScopedLock sl(m_PlayMutex);
	return m_SpectralModelPlayer.playHead();
}

void PantomimePlayer::seek(int pos, Whence whence) {
	ScopedLock sl(m_PlayMutex);
	int oldPlayhead = m_SpectralModelPlayer.playHead();
	m_SpectralModelPlayer.seek(pos, whence);
	int newPlayhead = m_SpectralModelPlayer.playHead();
	
	if (newPlayhead < oldPlayhead) {
		buildSampleQueue();
	}
	
	if (m_SampleQueue.size() > 0) {
		bool keepTrimmming = (m_SampleQueue.top()->smsFrame < newPlayhead);
		while (keepTrimmming) {
			m_SampleQueue.pop();
			keepTrimmming = (m_SampleQueue.size() > 0);
			if (keepTrimmming) {
				keepTrimmming = (m_SampleQueue.top()->smsFrame < newPlayhead);
			}
		}
	}
}

int PantomimePlayer::length() const {
	return m_SpectralModelPlayer.length();
}

void PantomimePlayer::runThread() {
	m_IsRunning = true;
	m_KeepRunning = true;
	while (m_KeepRunning) {
		{
			ScopedLock sl(m_PlayMutex);
			bool keepPlaying = (m_SampleQueue.size() > 0);
			if (keepPlaying) {
				keepPlaying = (m_SampleQueue.top()->smsFrame <= 
							   m_SpectralModelPlayer.playHead());
			}
			
			while (keepPlaying) {
				const InstrumentState& state = m_SampleQueue.top()->instrumentState;
				set<InstrumentListener*>::iterator listenerIter;
				for (listenerIter = m_Listeners.begin();
					 listenerIter != m_Listeners.end();
					 listenerIter++) {
					(*listenerIter)->instrumentCallback(NULL, state);
				}
				
				m_SampleQueue.pop();
				keepPlaying = (m_SampleQueue.size() > 0);
				if (keepPlaying) {
					keepPlaying = (m_SampleQueue.top()->smsFrame <= 
								   m_SpectralModelPlayer.playHead());
				}
			}
		}
		dag_msleep(1);
	}
	m_IsRunning = false;
}

void PantomimePlayer::buildSampleQueue() {
	while (!m_SampleQueue.empty()) {
		m_SampleQueue.pop();
	}
	
	if (m_CurrentPantomime != NULL) {
		for (size_t i = 0; i < m_CurrentPantomime->size(); i++) {
			m_SampleQueue.push(&m_CurrentPantomime->at(i));
		}
	}
}